package org.zzk.handler;


import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zzk.dao.ChessPacket;
import org.zzk.dao.CommandType;

import java.nio.charset.StandardCharsets;
import java.util.List;

@ChannelHandler.Sharable
public class ChessPacketCodecHandler extends MessageToMessageCodec<ByteBuf, ChessPacket> {
    public static final ChessPacketCodecHandler INSTANCE = new ChessPacketCodecHandler();
    private static final Logger logger = LoggerFactory.getLogger(ChessPacketCodecHandler.class);

    @Override
    protected void encode(ChannelHandlerContext ctx, ChessPacket packet, List<Object> out) {
        out.add(encode(packet.getCommand(), packet.getData()));
    }

    public static ByteBuf encode(CommandType command, JsonObject data) {
        byte[] jsonBytes = data.toString().getBytes(StandardCharsets.UTF_8);

        ByteBuf buf = Unpooled.buffer(11 + jsonBytes.length);
        buf.writeInt(0x88E4C5AA); // magic
        buf.writeByte(1);         // version
        buf.writeByte(0);         // algorithm (0=JSON)
        buf.writeByte(command.getCode());    // command
        buf.writeInt(jsonBytes.length); // length
        buf.writeBytes(jsonBytes); // data

        logger.info(data.toString());


        return buf;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        if (in.readableBytes() < 11) return; // 头部长度

        in.markReaderIndex();
        in.skipBytes(4);
        in.skipBytes(1);
        in.skipBytes(1);

        byte command = in.readByte();
        int length = in.readInt();

        if (in.readableBytes() < length) {
            in.resetReaderIndex();
            return;
        }

        byte[] data = new byte[length];
        in.readBytes(data);

        try {
            String jsonStr = new String(data, StandardCharsets.UTF_8);
            JsonObject json = JsonParser.parseString(jsonStr).getAsJsonObject();

            logger.info(json.toString());

            out.add(new ChessPacket(CommandType.fromCode(command), json));
        } catch (Exception e) {
            ctx.writeAndFlush(buildErrorPacket());
        }
    }

    private ByteBuf buildErrorPacket() {
        JsonObject json = new JsonObject();
        json.addProperty("error", "协议解析错误");
        return encode(CommandType.ERROR, json);
    }
}
